﻿using System.ComponentModel;
using System.Linq;
using System.Windows;
using Fayshine.VA.Helpers;
using Fayshine.VA.RIAService.Web;
using Fayshine.VA.Controls;
using Fayshine.VA.Models;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System;
using System.Threading;

namespace Fayshine.VA.ViewModels
{
    public delegate void ResetRealTimeChartEventHandler();
    public delegate void AppendGatePassengerFlowEventHandler(string name, bool isIn, List<GatePassengerFlow> gatePassengerFlows);
    public class PassengerFlowViewModel : INotifyPropertyChanged
    {
        #region Private Fields

        private FayshineDomainContext m_Context = null;
        private Timer m_RealTimer = null;
        private MonitorAreaGateExt m_SelectAreaGateExt = new MonitorAreaGateExt();
        private string m_CurveXTitle = string.Empty;
        private string m_CurveYTitle = string.Empty;
        private string m_CurveTitle = string.Empty;

        public event ResetRealTimeChartEventHandler ResetRealTimeEventHandler;
        public event AppendGatePassengerFlowEventHandler AppendGatePassengerFlow;
        #endregion

        public PassengerFlowViewModel()
        {
            this.AreaPassengerFlows = new PagedObservableCollectionView<RealTimePassengerFlow>();
            this.MonitorAreaGateExts = new ObservableCollection<MonitorAreaGateExt>();
            this.AreaExtends = new ObservableCollection<AreaExtend>();
            this.GatePassengerFlows = new ObservableCollection<GatePassengerFlow>();
            m_Context = new FayshineDomainContext();
        }

        #region Properties

        public PagedObservableCollectionView<RealTimePassengerFlow> AreaPassengerFlows
        {
            get;
            set;
        }

        public ObservableCollection<GatePassengerFlow> SelectedAreaInPassengerFlows
        {
            get;
            set;
        }

        public ObservableCollection<GatePassengerFlow> SelectedAreaOutPassengerFlows
        {
            get;
            set;
        }

        public ObservableCollection<AreaExtend> AreaExtends
        {
            get;
            set;
        }

        public ObservableCollection<MonitorAreaGateExt> MonitorAreaGateExts
        {
            get;
            set;
        }

        public MonitorAreaGateExt SelectedMonitorAreaGateExt
        {
            get
            {
                return m_SelectAreaGateExt;
            }
            set
            {
                m_SelectAreaGateExt = value;
                NofityPropertyChanged("SelectedMonitorAreaGateExt");
            }
        }

        public string CurveXTitle
        {
            get
            {
                return m_CurveXTitle;
            }
            set
            {
                m_CurveXTitle = value;
                NofityPropertyChanged("CurveXTitle");
            }
        }

        public string CurveYTitle
        {
            get
            {
                return m_CurveYTitle;
            }
            set
            {
                m_CurveYTitle = value;
                NofityPropertyChanged("CurveYTitle");
            }
        }

        public string CurveTitle
        {
            get
            {
                return m_CurveTitle;
            }
            set
            {
                m_CurveTitle = value;
                NofityPropertyChanged("CurveTitle");
            }
        }

        #endregion

        #region Public Methods

        public void GetAllAreas()
        {
            var getAreasQuery = m_Context.GetAreasQuery();
            var loadShopsOperation = m_Context.Load(getAreasQuery, (s) =>
            {
                if (!s.HasError)
                {
                    AreaExtend tempAreaExt = null;
                    s.Entities.ToList().ForEach(e =>
                    {
                        tempAreaExt = new AreaExtend();
                        tempAreaExt.ID = e.ID;
                        tempAreaExt.Name = e.Name;
                        tempAreaExt.Tag = e;
                        tempAreaExt.IsSelected = false;
                        this.AreaExtends.Add(tempAreaExt);
                    });
                }
                else
                {
                    MessageBox.Show(s.Error.Message + s.Error.StackTrace);
                }
                BusyIndicator indicator = Application.Current.RootVisual as BusyIndicator;
                indicator.IsBusy = false;
            }, true);
        }

        public bool IsConditionSelected()
        {
            bool isSelected = true;

            var selectedArea = this.AreaExtends.Where(a => a.IsSelected);

            if (selectedArea.Any())
            {
                var selectGates = this.MonitorAreaGateExts.Where(m => m.IsSelected);
                if (selectGates.Any())
                {
                    isSelected = true;
                }
                else
                {
                    isSelected = false;
                }
            }
            else
            {
                isSelected = false;
            }

            return isSelected;
        }

        #endregion

        #region 实时曲线

        public void MonitorSelectAreaGateExt(bool isIn)
        {
            if (m_RealTimer != null)
            {
                m_RealTimer.Change(Timeout.Infinite, Timeout.Infinite);
            }

            m_RealTimer = new Timer(delegate(object state) { StartToMonitorRealTimePassengerFlow(isIn); }, null, 0, 1 * 60 * 1000);
        }

        public void SelectAreasChanged(List<area> areas,bool isIncludeArea)
        {
            if (areas.Count > 0)
            {
                this.MonitorAreaGateExts.Clear();
                MonitorAreaGateExt tempMonitorExt;
                if (areas.Count == 1)
                {
                    areas[0].gates.OrderBy(o => o.ID).each(e =>
                    {
                        tempMonitorExt = new MonitorAreaGateExt();
                        tempMonitorExt.ID = e.ID;
                        tempMonitorExt.ParentID = areas[0].ID;
                        tempMonitorExt.Name = e.Name;
                        tempMonitorExt.TypeID = 0;
                        tempMonitorExt.IsSelected = true;
                        this.MonitorAreaGateExts.Add(tempMonitorExt);
                    });

                    if (isIncludeArea)
                    {
                        tempMonitorExt = new MonitorAreaGateExt();
                        tempMonitorExt.ID = areas[0].ID;
                        tempMonitorExt.ParentID = null;
                        tempMonitorExt.Name = "总计";
                        tempMonitorExt.TypeID = 1;
                        tempMonitorExt.IsSelected = true;
                        this.MonitorAreaGateExts.Add(tempMonitorExt);
                    }
                }
                else
                {
                    areas.each(a =>
                    {
                        tempMonitorExt = new MonitorAreaGateExt();
                        tempMonitorExt.ID = a.ID;
                        tempMonitorExt.Name = a.Name;
                        tempMonitorExt.ParentID = a.ParentID;
                        tempMonitorExt.TypeID = 1;
                        tempMonitorExt.IsSelected = true;
                        this.MonitorAreaGateExts.Add(tempMonitorExt);
                    });

                    tempMonitorExt = new MonitorAreaGateExt();
                    tempMonitorExt.ID = -1;
                    tempMonitorExt.Name = "所选店铺总和";
                    tempMonitorExt.ParentID = null;
                    tempMonitorExt.TypeID = 2;
                    tempMonitorExt.IsSelected = true;
                    this.MonitorAreaGateExts.Add(tempMonitorExt);
                }

            }
        }

        private void StartToMonitorRealTimePassengerFlow(bool isIn)
        {
            if (ResetRealTimeEventHandler != null)
            {
                ResetRealTimeEventHandler();
            }

            var selectAreaExt = this.AreaExtends.Where(a => a.IsSelected).ToList();
            List<int> monitorAreaIDs = new List<int>();
            selectAreaExt.each(s => { monitorAreaIDs.Add(s.ID); });
            bool isSingleArea = monitorAreaIDs.Count == 1 ? true : false;

            var getRealTimePassengerQuery = m_Context.GetRealTimePassengerflowbyMinQuery(monitorAreaIDs);
            var loadRealTimePassenger = m_Context.Load(getRealTimePassengerQuery, (s) =>
            {
                if (!s.HasError)
                {
                    this.CurveXTitle = string.Format("{0} 进", this.SelectedMonitorAreaGateExt.Name);
                    this.CurveYTitle = string.Format("{0} 出", this.SelectedMonitorAreaGateExt.Name);
                    this.CurveTitle = string.Format("{0} 实时曲线", this.SelectedMonitorAreaGateExt.Name);
                    this.AreaPassengerFlows.Clear();

                    RealTimePassengerFlow tempRealTimeFlow;
                    List<passengerflowbymin> tempPassengerFlows = new List<passengerflowbymin>();

                    bool neetToSelect = true;
                    this.MonitorAreaGateExts.each(m =>
                    {
                        if (isSingleArea)
                        {
                            neetToSelect = m.IsSelected;
                        }
                        if (neetToSelect)
                        {
                            List<GatePassengerFlow> tempGatePassengerFlows = new List<GatePassengerFlow>();
                            tempPassengerFlows.Clear();
                            if (m.TypeID == 0)
                            {
                                tempPassengerFlows = s.Entities.Where(entity => entity.gateID == m.ID).ToList();
                            }
                            else if (m.TypeID == 1)
                            {
                                var ids = GetGateIDsByArea(m.ID);
                                tempPassengerFlows = s.Entities.Where(entity => ids.Contains(entity.gateID)).ToList();
                            }
                            else if (m.TypeID == 2)
                            {
                                tempPassengerFlows = s.Entities.ToList();
                            }

                            DateTime dtNow = DateTime.Now;
                            DateTime dtRangeStart = new DateTime(dtNow.Year, dtNow.Month, dtNow.Day, dtNow.Hour, ((int)(dtNow.Minute / 5)) * 5, 0);
                            DateTime dtRangeEnd = dtRangeStart.AddMinutes(5);

                            tempRealTimeFlow = GetGateRealTimePassengerFlow(m, tempPassengerFlows, isSingleArea, dtRangeStart, dtRangeEnd);
                            this.AreaPassengerFlows.Add(tempRealTimeFlow);

                            tempGatePassengerFlows = GetRealTimeGatePassengerFlow(m.Name, isIn, tempPassengerFlows);
                            //tempGatePassengerFlows.Add(GetEndPassengerFlow(m.Name));
                            if (AppendGatePassengerFlow != null)
                            {

                                AppendGatePassengerFlow(m.Name, isIn, tempGatePassengerFlows);
                            }
                        }
                    });
                }
                else
                {
                    MessageBox.Show(s.Error.Message + s.Error.StackTrace);
                }
                BusyIndicator indicator = Application.Current.RootVisual as BusyIndicator;
                indicator.IsBusy = false;

            }, true);
        }

        private List<int> GetGateIDsByArea(int areaID)
        {
            List<int> ids = new List<int>();

            if (areaID >= 0)
            {
                var area = this.AreaExtends.Where(a => a.ID == areaID).FirstOrDefault().Tag as area;
                if (area != null)
                {
                    area.gates.each(g => { ids.Add(g.ID); });
                }
            }
            return ids;
        }

        private RealTimePassengerFlow GetGateRealTimePassengerFlow(MonitorAreaGateExt targetAreaGate, List<passengerflowbymin> passengerflows, bool isSingleArea, DateTime dtRangeStart, DateTime dtRangeEnd)
        {
            RealTimePassengerFlow gateRealPassengerFlow = new RealTimePassengerFlow();
            if ((targetAreaGate.TypeID == 1 && isSingleArea) || targetAreaGate.TypeID == 2)
            {
                gateRealPassengerFlow.GateID = -1;
                gateRealPassengerFlow.GateName = "总计";
            }
            else
            {
                gateRealPassengerFlow.GateID = targetAreaGate.ID;
                gateRealPassengerFlow.GateName = targetAreaGate.Name;
            }


            IEnumerable<int?> currentIns = from t in passengerflows
                                           where t.dt >= dtRangeStart && t.dt < dtRangeEnd && t.isIn == true
                                           select t.count;
            IEnumerable<int?> currentOuts = from t in passengerflows
                                            where t.dt >= dtRangeStart && t.dt < dtRangeEnd && t.isIn == false
                                            select t.count;

            gateRealPassengerFlow.CurrentIn = currentIns.Sum().Value;
            gateRealPassengerFlow.CurrentOut = currentOuts.Sum().Value;
            gateRealPassengerFlow.TodayIn = passengerflows.Where(p => p.isIn == true).Sum(s => s.count).Value;
            gateRealPassengerFlow.TodayOut = passengerflows.Where(p => p.isIn == false).Sum(s => s.count).Value;

            int minutes = (DateTime.Now.Hour * 60 + DateTime.Now.Minute) / 5;
            if (passengerflows.Where(p => p.isIn == true).Any())
            {
                gateRealPassengerFlow.AvageIn = gateRealPassengerFlow.TodayIn / passengerflows.Count;
            }
            else
            {
                gateRealPassengerFlow.AvageIn = 0;
            }
            if (passengerflows.Where(p => p.isIn == false).Any())
            {
                gateRealPassengerFlow.AvageOut = gateRealPassengerFlow.TodayOut / passengerflows.Count;
            }

            else
            {
                gateRealPassengerFlow.AvageOut = 0;
            }
            gateRealPassengerFlow.CurrentPassenger = gateRealPassengerFlow.CurrentIn + gateRealPassengerFlow.CurrentOut;
            gateRealPassengerFlow.AvagePassenger = gateRealPassengerFlow.AvageIn + gateRealPassengerFlow.AvageOut;

            return gateRealPassengerFlow;
        }

        private GatePassengerFlow GetGatePassengerFlow(string name, passengerflowbymin passenger)
        {
            GatePassengerFlow flow = new GatePassengerFlow();
            flow.Name = name;
            flow.IsIn = passenger.isIn;
            if (passenger.isIn.Value)
            {
                flow.InCount = passenger.count.Value;
            }
            else
            {
                flow.OutCount = passenger.count.Value;
            }

            flow.DisplayTime = passenger.dt.Value;

            return flow;
        }

        private GatePassengerFlow GetStartPassengerFlow(string name)
        {
            GatePassengerFlow flow = new GatePassengerFlow();
            flow.Name = name;

            flow.InCount = 0;

            flow.OutCount = 0;

            flow.DisplayTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 0, 0, 0); ;

            return flow;
        }

        private GatePassengerFlow GetEndPassengerFlow(string name)
        {
            GatePassengerFlow flow = new GatePassengerFlow();
            flow.Name = name;

            flow.InCount = 0;

            flow.OutCount = 0;

            flow.DisplayTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 23, 59, 59); ;

            return flow;
        }

        private List<GatePassengerFlow> GetRealTimeGatePassengerFlow(string name, bool isIn, List<passengerflowbymin> passengers)
        {
            List<GatePassengerFlow> gatePassengerFlows = new List<GatePassengerFlow>();

            DateTime? startTime = (from a in passengers
                                   select a.dt).Min();

            DateTime? endTime = (from a in passengers
                                 select a.dt).Max();

            DateTime dtNow = DateTime.Now;
            endTime = endTime > dtNow ? endTime : dtNow;

            GatePassengerFlow tempPassenger = null;
            if (startTime != null && endTime != null)
            {
                DateTime? dt = startTime;
                while (dt <= endTime)
                {
                    var existPassenger = passengers.Where(p => p.dt == dt && p.isIn == isIn).FirstOrDefault();
                    if (existPassenger != null)
                    {
                        tempPassenger = GetGatePassengerFlow(name, existPassenger);
                    }
                    else
                    {
                        tempPassenger = new GatePassengerFlow();
                        tempPassenger.Name = name;
                        tempPassenger.InCount = 0;
                        tempPassenger.OutCount = 0;
                        tempPassenger.DisplayTime = dt.Value;
                    }
                    gatePassengerFlows.Add(tempPassenger);
                    dt = dt.Value.AddMinutes(5);
                }
            }
            return gatePassengerFlows;
        }

        #endregion

        #region 查询统计

        public ObservableCollection<GatePassengerFlow> GatePassengerFlows
        {
            get;
            set;
        }

        public void QueryPassengerFlowByTime(bool isIn, DateTime startTime, DateTime endTime)
        {
            var selectAreaExt = this.AreaExtends.Where(a => a.IsSelected).ToList();
            List<int> monitorAreaIDs = new List<int>();
            selectAreaExt.each(s => { monitorAreaIDs.Add(s.ID); });
            bool isSingleArea = monitorAreaIDs.Count == 1 ? true : false;

            var getRealTimePassengerQuery = m_Context.GetPassengerflowbyMinByTimeQuery(monitorAreaIDs, startTime, endTime);

            var loadRealTimePassenger = m_Context.Load(getRealTimePassengerQuery, (s) =>
            {
                if (!s.HasError)
                {
                    this.CurveTitle = GetColumnChartTitle(isIn, isSingleArea, selectAreaExt[0].Name, startTime, endTime);
                    this.AreaPassengerFlows.Clear();

                    RealTimePassengerFlow tempRealTimeFlow;
                    List<passengerflowbymin> tempPassengerFlows = new List<passengerflowbymin>();
                    this.GatePassengerFlows.Clear();
                    this.MonitorAreaGateExts.each(m =>
                    {
                        //List<GatePassengerFlow> tempGatePassengerFlows = new List<GatePassengerFlow>();
                        tempPassengerFlows.Clear();
                        if (m.TypeID == 0)
                        {
                            tempPassengerFlows = s.Entities.Where(entity => entity.gateID == m.ID).ToList();
                        }
                        else if (m.TypeID == 1)
                        {
                            var ids = GetGateIDsByArea(m.ID);
                            tempPassengerFlows = s.Entities.Where(entity => ids.Contains(entity.gateID)).ToList();
                        }
                        else if (m.TypeID == 2)
                        {
                            tempPassengerFlows = s.Entities.ToList();
                        }

                        DateTime dtNow = DateTime.Now;
                        DateTime dtRangeStart = new DateTime(dtNow.Year, dtNow.Month, dtNow.Day, dtNow.Hour, ((int)(dtNow.Minute / 5)) * 5, 0);
                        DateTime dtRangeEnd = dtRangeStart.AddMinutes(5);

                        tempRealTimeFlow = GetGateRealTimePassengerFlow(m, tempPassengerFlows, isSingleArea, dtRangeStart, dtRangeEnd);

                        this.AreaPassengerFlows.Add(tempRealTimeFlow);

                        GatePassengerFlow tempGateFlow;
                        if (tempRealTimeFlow.GateID != -1)
                        {
                            tempGateFlow = new GatePassengerFlow();
                            tempGateFlow.Name = tempRealTimeFlow.GateName;
                            tempGateFlow.IsIn = isIn;
                            if (tempGateFlow.IsIn.Value)
                            {
                                tempGateFlow.InCount = tempRealTimeFlow.TodayIn;
                            }
                            else
                            {
                                tempGateFlow.OutCount = tempRealTimeFlow.TodayOut;
                            }

                            GatePassengerFlows.Add(tempGateFlow);
                        }
                    });
                }
                else
                {
                    MessageBox.Show(s.Error.Message + s.Error.StackTrace);
                }
                BusyIndicator indicator = Application.Current.RootVisual as BusyIndicator;
                indicator.IsBusy = false;

            }, true);
        }

        private string GetColumnChartTitle(bool isIn, bool isGate, string areaName, DateTime startTime, DateTime endTime)
        {
            string title = "客流监控情况";
            string stStr = String.Format("{0:d/M/yyyy HH:mm:ss}", startTime);
            string etStr = String.Format("{0:d/M/yyyy HH:mm:ss}", endTime);
            if (isIn)
            {
                if (isGate)
                {
                    title = string.Format("{0} 至 {1} {2} 各门店进客流", stStr, etStr, areaName);
                }
                else
                {
                    title = string.Format("{0} 至 {1} 各店铺进客流", stStr, etStr);
                }
            }
            else
            {
                if (isGate)
                {
                    title = string.Format("{0} 至 {1} {2} 各门店出客流", stStr, etStr, areaName);
                }
                else
                {
                    title = string.Format("{0} 至 {1} 各店铺出客流", stStr, etStr);
                }
            }
            return title;
        }

        #endregion

        #region INotifyPropertyChanged Interface

        public event PropertyChangedEventHandler PropertyChanged;
        public void NofityPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
    }
}
